package main

import "fmt"

func main() {
	fmt.Println("13. 指针")

	// 什么是指针
	fmt.Println("\n--- 什么是指针 ---")

	// 声明变量
	var x int = 42
	fmt.Printf("变量 x 的值: %d\n", x)
	fmt.Printf("变量 x 的地址: %p\n", &x)

	// 声明指针变量
	var p *int // p 是指向 int 的指针
	p = &x     // 将 x 的地址赋给指针 p
	fmt.Printf("指针 p 的值(地址): %p\n", p)
	fmt.Printf("指针 p 指向的值: %d\n", *p) // 解引用

	// 直接声明并初始化指针
	y := 100
	ptr := &y
	fmt.Printf("y = %d, &y = %p, ptr = %p, *ptr = %d\n", y, &y, ptr, *ptr)

	// 通过指针修改值
	fmt.Printf("修改前 y = %d\n", y)
	*ptr = 200
	fmt.Printf("通过指针修改后 y = %d\n", y)

	// 指针的零值是 nil
	var nilPtr *int
	fmt.Printf("nil 指针: %v\n", nilPtr)

	// 空指针判断
	if nilPtr == nil {
		fmt.Println("ptr 是空指针")
	}

	// 指针运算 (Go 中不支持指针运算，但可以比较)
	fmt.Println("\n--- 指针比较 ---")
	a := 10
	b := 10
	ptrA := &a
	ptrB := &b
	ptrC := &a

	fmt.Printf("ptrA: %p, ptrB: %p, ptrC: %p\n", ptrA, ptrB, ptrC)
	fmt.Printf("ptrA == ptrB: %t\n", ptrA == ptrB) // 不同变量的地址不同
	fmt.Printf("ptrA == ptrC: %t\n", ptrA == ptrC) // 同一变量的地址相同

	// 指针与数组
	fmt.Println("\n--- 指针与数组 ---")
	arr := [3]int{10, 20, 30}
	fmt.Printf("数组: %v\n", arr)

	// 指向数组的指针
	arrPtr := &arr
	fmt.Printf("数组指针: %p\n", arrPtr)
	fmt.Printf("通过指针访问数组: %v\n", *arrPtr)

	// 指向数组元素的指针
	elemPtr := &arr[0]
	fmt.Printf("第一个元素的指针: %p, 值: %d\n", elemPtr, *elemPtr)
	*elemPtr = 100
	fmt.Printf("修改后数组: %v\n", arr)

	// 指针与切片
	fmt.Println("\n--- 指针与切片 ---")
	slice := []int{1, 2, 3, 4, 5}
	fmt.Printf("切片: %v\n", slice)

	// 切片本身就是引用类型，内部包含指向底层数组的指针
	slice2 := slice
	slice2[0] = 999
	fmt.Printf("修改 slice2 后 slice: %v\n", slice) // 原切片也被修改
	fmt.Printf("修改 slice2 后 slice2: %v\n", slice2)

	// 指针与结构体
	fmt.Println("\n--- 指针与结构体 ---")

	type Person struct {
		Name string
		Age  int
	}

	// 创建结构体实例
	person := Person{Name: "张三", Age: 25}
	fmt.Printf("person: %+v\n", person)

	// 指向结构体的指针
	personPtr := &person
	fmt.Printf("personPtr: %p\n", personPtr)
	fmt.Printf("通过指针访问: %+v\n", *personPtr)

	// 通过指针访问结构体字段 (Go 提供了语法糖，可以省略 *)
	fmt.Printf("personPtr.Name: %s\n", personPtr.Name) // 等价于 (*personPtr).Name
	fmt.Printf("personPtr.Age: %d\n", personPtr.Age)   // 等价于 (*personPtr).Age

	// 通过指针修改结构体字段
	personPtr.Name = "李四"
	personPtr.Age = 30
	fmt.Printf("修改后 person: %+v\n", person)

	// 使用 new 函数创建指针
	fmt.Println("\n--- 使用 new 函数 ---")
	intPtr := new(int) // 创建指向 int 的指针，值为 0
	fmt.Printf("new(int) 创建的指针: %p, 值: %d\n", intPtr, *intPtr)

	strPtr := new(string) // 创建指向 string 的指针，值为 ""
	fmt.Printf("new(string) 创建的指针: %p, 值: %s\n", strPtr, *strPtr)

	personPtr2 := new(Person) // 创建指向 Person 的指针，字段为零值
	fmt.Printf("new(Person) 创建的指针: %p, 值: %+v\n", personPtr2, *personPtr2)

	// 指针作为函数参数
	fmt.Println("\n--- 指针作为函数参数 ---")

	// 值传递 - 不会修改原值
	num := 10
	fmt.Printf("调用 modifyValue 前 num = %d\n", num)
	modifyValue(num)
	fmt.Printf("调用 modifyValue 后 num = %d\n", num)

	// 指针传递 - 会修改原值
	fmt.Printf("调用 modifyValueByPointer 前 num = %d\n", num)
	modifyValueByPointer(&num)
	fmt.Printf("调用 modifyValueByPointer 后 num = %d\n", num)

	// 指针与函数返回值
	fmt.Println("\n--- 指针作为函数返回值 ---")

	// 返回局部变量的指针是安全的
	localPtr := createIntPointer(42)
	fmt.Printf("createIntPointer 返回的指针: %p, 值: %d\n", localPtr, *localPtr)

	// 返回结构体指针
	personPtr3 := createPersonPointer("王五", 35)
	fmt.Printf("createPersonPointer 返回的指针: %p, 值: %+v\n", personPtr3, *personPtr3)

	// 双重指针
	fmt.Println("\n--- 双重指针 ---")
	value := 100
	ptr1 := &value // 指向 value 的指针
	ptr2 := &ptr1  // 指向 ptr1 的指针（双重指针）
	fmt.Printf("value: %d\n", value)
	fmt.Printf("ptr1: %p, *ptr1: %d\n", ptr1, *ptr1)
	fmt.Printf("ptr2: %p, *ptr2: %p, **ptr2: %d\n", ptr2, *ptr2, **ptr2)

	// 通过双重指针修改值
	**ptr2 = 200
	fmt.Printf("通过双重指针修改后 value: %d\n", value)

	// 指针的实用示例：交换两个值
	fmt.Println("\n--- 指针实用示例：交换值 ---")
	m, n := 10, 20
	fmt.Printf("交换前: m = %d, n = %d\n", m, n)
	swap(&m, &n)
	fmt.Printf("交换后: m = %d, n = %d\n", m, n)
}

// 值传递示例函数
func modifyValue(x int) {
	x = 100
	fmt.Printf("modifyValue 内部 x = %d\n", x)
}

// 指针传递示例函数
func modifyValueByPointer(ptr *int) {
	*ptr = 100
	fmt.Printf("modifyValueByPointer 内部 *ptr = %d\n", *ptr)
}

// 返回指针的函数
func createIntPointer(value int) *int {
	// 返回局部变量的地址是安全的，Go 会自动处理内存
	temp := value
	return &temp
}

// 返回结构体指针的函数
func createPersonPointer(name string, age int) *Person {
	// 返回局部变量的地址是安全的
	person := Person{Name: name, Age: age}
	return &person
}

// 交换两个值的函数
func swap(a, b *int) {
	temp := *a
	*a = *b
	*b = temp
}
